<template>
  <view class="cl-updata">
    <view :style="[listRowStyle]" class="file-list">

      <view v-for="(item, index) in previewList" :key="index" :style="[rowStyle]"
            class="file-list-row" @tap="clickSelectedFile(item, index)">

        <image
            v-if="fileUrlType(item) === 'image'"
            :src="item.path"
            :style="[imgStyle]"
            class="_image"
            mode="aspectFill">
        </image>

        <view v-else :style="[imgStyle]" class="_video">

          <!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
          <video
              v-if="!autoUpload || cloudType === 'other'"
              :controls="false"
              :enable-progress-gesture="false"
              :show-center-play-btn="false"
              :show-fullscreen-btn="false"
              :show-loading="false"
              :show-play-btn="false"
              :src="item.path"
              :style="[imgStyle]"
              class="_video">
            <view class="play" @tap="previewVideo(item, index)">
              <image :src="playImg" mode="widthFix" style="width: 100%;"></image>
            </view>
          </video>

          <!-- #endif -->

          <!-- #ifdef APP-PLUS -->
          <video
              v-if="cloudType === 'other'"
              :controls="false"
              :enable-progress-gesture="false"
              :poster="item.path"
              :show-center-play-btn="false"
              :show-fullscreen-btn="false"
              :show-loading="false"
              :show-play-btn="false"
              :src="item.path"
              :style="[imgStyle]"
              class="_video">
            <cover-image :src="playImg" class="app_play" @tap="previewVideo(item, index)"></cover-image>
            <cover-view v-if="remove" class="remove" @tap="deleteSelectedFile(item, index)">
              <cover-image :src="deleteImg" class="image" mode="widthFix"
                           @tap="deleteSelectedFile(item, index)"></cover-image>
            </cover-view>
          </video>
          <!-- #endif -->

          <!-- #ifndef MP-WEIXIN || MP-ALIPAY || APP-PLUS -->
          <video
              v-if="cloudType === 'other'"
              :autoplay="false"
              :controls="false"
              :enable-progress-gesture="false"
              :show-center-play-btn="false"
              :show-fullscreen-btn="false"
              :show-loading="false"
              :show-play-btn="false"
              :src="item.path"
              :style="[imgStyle]"
              class="_video">
            <cover-view class="play" @tap="previewVideo(item, index)">
              <cover-image :src="playImg" mode="widthFix" style="width: 100%;"></cover-image>
            </cover-view>
          </video>

          <!-- #endif -->

          <template v-else>
            <cl-image :cloudType="cloudType" :src="(item.poster || item.path)" :style="[imgStyle]"
                      class="pay"></cl-image>

            <view class="play" @tap="previewVideo(item, index)">
              <image :src="playImg" class="play-img" mode="widthFix"></image>
            </view>
          </template>

        </view>

        <view v-if="remove" class="remove" @tap.stop="deleteSelectedFile(item, index)">
          <image :src="deleteImg" class="image" mode="widthFix"></image>
        </view>
      </view>

      <view v-if="add && FileList.length < max" :style="[rowStyle]" class="file-list-row" @tap="selectFileTypeOnAdd">
        <slot name="addImg">
          <div class="add-image">
            <image :src="addImg" class="_image" mode="widthFix"></image>
          </div>
        </slot>
      </view>
    </view>


    <view v-if="tempVideoUrl" class="mask">
      <image :src="closeImg" class="_root" mode="widthFix" @tap="tempVideoUrl = ''"></image>

      <view class="block" @tap.stop>
        <video :src="tempVideoUrl" autoplay class="block_video"></video>
      </view>
    </view>
  </view>
</template>

<script>
import ClImage from '../cl-image/cl-image.vue'

export default {
  name: "cl-upload",
  components: {ClImage},
  props: {
    //受控图片列表
    // #ifdef VUE2
    value: {
      type: Array,
      default: () => [],
    },
    // #endif

    // #ifdef VUE3
    modelValue: {
      type: Array,
      default: () => [],
    },
    // #endif

    // 存储云类型 oss阿里云  vframe七牛云   process腾讯云  other其他
    cloudType: {
      type: String,
      default: 'oss'
    },
    // 标识符,即后端接口参数名
    fileName: {
      type: String,
      default: 'file'
    },
    // 文件类型 'image', 'video', 'all'
    fileType: {
      type: String,
      default: 'all'
    },
    // 上传图片参数
    imageFormData: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 上传视频参数
    videoFromData: {
      type: Object,
      default: () => {
      }
    },

    // 必选参数，上传的地址
    action: {
      type: String,
      default: ''
    },

    // 启用目录, 仅unicloud阿里云支持
    // https://uniapp.dcloud.net.cn/uniCloud/storage.html#storage-dir
    cloudPathAsRealPath: {
      type: Boolean,
      default: false
    },

    // 设置上传的请求头部
    headers: {
      type: Object,
      default: () => {
      }
    },

    // 上传时附带的额外参数
    data: {
      type: Object,
      default: () => {
      }
    },

    // 是否开启预览图片
    isPreviewImage: {
      type: Boolean,
      default: true
    },

    // 图片指示器样式，可取值："default" - 底部圆点指示器； "number" - 顶部数字指示器； "none" - 不显示指示器。
    indicator: {
      type: String,
      default: 'none'
    },
    // 是否在选取文件后立即进行上传
    autoUpload: {
      type: Boolean,
      default: true
    },
    // 是否显示删除按钮
    remove: {
      type: Boolean,
      default: true
    },
    // 是否添加按钮
    add: {
      type: Boolean,
      default: true
    },
    // 最多显示数量
    max: {
      type: Number,
      default: 9
    },
    // 视频最大上传数量
    maxVideo: {
      type: Number,
      default: 0
    },
    // 列表样式
    listStyle: {
      type: Object,
      default: () => {
      }
    },
    // 删除提示弹窗标题
    deleteTitle: {
      type: String,
      default: '提示'
    },
    // 删除提示弹窗文案
    deleteText: {
      type: String,
      default: '您确认要删除吗？'
    },
    // 加载文案
    loadingText: {
      type: String,
      default: '正在上传中...'
    },
    // 是否开启删除前钩子
    useBeforeDelete: {
      type: Boolean,
      default: false
    },
    // 是否开启上传前钩子
    useBeforeUpload: {
      type: Boolean,
      default: false
    },
    // 添加按钮图片
    addImg: {
      type: String,
      default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/bb1550b3-e0a8-4a90-a86f-00f8c6afa9fb.png'
    },
    // 播放按钮图片
    playImg: {
      type: String,
      default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/ae40402f-aa53-4344-b553-2322799bebd6.png'
    },
    // 删除按钮图片
    deleteImg: {
      type: String,
      default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/d20177a5-417e-4c5d-a266-1988361c543d.png'
    },
    // 关闭视频按钮图片
    closeImg: {
      type: String,
      default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/cde4362d-7ec7-4cac-a692-12e1f576be1e.png'
    },
  },
  data() {
    return {
      // 渲染列表
      FileList: [],

      // 预览视频地址
      tempVideoUrl: '',

      // 临时文件列表
      tempFile_paths: [],

    };
  },
  watch: {
    // #ifdef VUE2
    'value': {
      handler: function (newVal, oldVal) {
        this.FileList = newVal;
      },
      deep: true,
      immediate: true
    },
    // #endif

    // #ifdef VUE3
    'modelValue': {
      handler: function (newVal, oldVal) {
        this.FileList = newVal;
      },
      deep: true,
      immediate: true
    },
    // #endif
  },
  computed: {
    previewList() {
      return this.FileList.map(item => {
        return {
          path: item.path || item,
          poster: item.poster || ''
        }
      })
    },
    listRowStyle() {
      const style = {
        'grid-template-columns': `repeat(${this.listStyle?.columns || 4}, 1fr)`, // 每行数量
        'grid-column-gap': this.listStyle?.columnGap || '40rpx', // 行间距
        'grid-row-gap': this.listStyle?.rowGap || '40rpx', // 列间距
        'padding': this.listStyle?.padding || '0rpx' // 列表内边距
      }

      return style;
    },
    rowStyle() {
      const {height = '140rpx', ratio} = this.listStyle || {};
      const style = {
        'aspect-ratio': height ? '' : ratio || '1/1', // 图片比例
        'height': height,
      };

      return style;
    },

    imgStyle() {
      const style = {
        'border-radius': this.listStyle?.radius || '6rpx', // 图片圆角
      }
      return style;
    }
  },
  methods: {
    /**
     * 删除已选择文件
     * @param {object} item 文件信息
     * @param {number} selectedFileIndex 文件索引
     * */
    deleteSelectedFile(item, selectedFileIndex) {

      const fileToDelete = this.FileList[selectedFileIndex];

      // 删除前钩子
      if (this.useBeforeDelete) {
        this.$emit('beforeDelete', fileToDelete, selectedFileIndex, () => {
          return deleteFileFromList()
        })
      }

      if (!this.useBeforeDelete) {
        uni.showModal({
          title: this.deleteTitle,
          content: this.deleteText,
          success: (res) => {
            if (res.confirm) {
              deleteFileFromList()
            }
          }
        });
      }

      const deleteFileFromList = () => {
        const tempFileIndex = this.tempFile_paths.indexOf(item || item.path);

        if (tempFileIndex > -1) {
          this.tempFile_paths.splice(tempFileIndex, 1)
        }

        this.FileList.splice(selectedFileIndex, 1)

        // #ifdef VUE2
        this.$emit('input', this.FileList)
        // #endif

        // #ifdef VUE3
        this.$emit("update:modelValue", this.FileList);
        // #endif
      }

    },

    /**
     * 点击已选择文件
     * @param {object} item 文件信息
     * @param {number} index 文件索引
     * */
    clickSelectedFile(item, index) {
      // this.previewImage(item?.path ?? item, index);
      this.$emit('onImage', {
        item,
        index
      })
    },

    /**
     * 点击选择图片按钮
     * */
    selectFileTypeOnAdd() {

      switch (this.fileType) {
        case 'image':
          this.handleFileSelection(1);
          break;
        case 'video':
          this.handleFileSelection(2);
          break;
        case 'all':
          uni.showActionSheet({
            itemList: ['相册', '视频'],
            success: (res) => {
              const tapIndex = res.tapIndex;
              if (tapIndex === 0) {
                this.handleFileSelection(1);
              } else {
                this.handleFileSelection(2);
              }
            },
            fail: (res) => {
              console.error(res.errMsg);
            }
          });
          break;
        default:
          this.handleFileSelection(1);
          break;
      }
    },


    /**
     * 从本地选择文件。
     * @param { number } updataType 选择类型 1:图片 2视频
     * */
    async handleFileSelection(updataType) {
      const that = this;
      if (updataType === 1) {

        const data = Object.assign({}, {
          // 最多可以选择的图片张数，默认9
          count: 9,
          // 仅对 mediaType 为 image 时有效，是否压缩所选文件
          // #ifndef MP-TOUTIAO
          sizeType: ['original', 'compressed'],
          // #endif
          // album 从相册选图，camera 使用相机，默认二者都有。
          sourceType: ['camera', 'album'],

          compress: false
        }, this.imageFormData)

        data['count'] = this.max - this.FileList.length

        uni.chooseImage({
          ...data,
          success: async (res) => {
            let tempFiles = res.tempFiles;
            const compress = that.imageFormData?.compress || false;
            let filteredFiles
            // 限制图片上传尺寸
            if (that.imageFormData?.size ?? false) {
              const maxSize = that.imageFormData.size * 1024 * 1024
              /*tempFiles.map((imgInfo, index) => {
                console.log(imgInfo.size,index)
                if (imgInfo.size > maxSize) {
                  tempFiles.splice(index, 1)
                }
              })*/
              filteredFiles = tempFiles.filter(imgInfo => {
                if (imgInfo.size <= maxSize) {
                  return imgInfo
                } else {
                  return that.$emit('onImageSize', imgInfo)
                }
              });
            }

            // 开启压缩图片
            if (compress) {
              const compressedImagePathList = filteredFiles.map(imageItem => {
                return that.compressImage(imageItem.path)
              })

              Promise.all(compressedImagePathList).then(result => {
                upload(result);
              })

            } else {
              upload(filteredFiles);
            }

            function upload(tempImages) {
              if (that.autoUpload) {
                tempImages.map(item => {
                  console.log("上传文件")
                  that.onBeforeUploadFile(item, 'image')
                })
              } else {
                that.FileList = [...that.FileList, ...tempImages]
                tempImages.map(item => {
                  that.tempFile_paths.push(item)
                })
              }
            }

          },
          fail(err) {
            console.error('选择图片失败', err)
            that.$emit('onError', err)
          }

        })
      }

      if (updataType === 2) {

        // 限制视频最大上传数量
        const VIDEO_REGEXP = /\.(mp4|flv|avi)/i
        const videoList = await that.FileList.filter(item => {
          const fileUrl = item?.url ?? item
          return VIDEO_REGEXP.test(fileUrl)
        })

        if (that.maxVideo > 0 && videoList.length >= that.maxVideo) {
          that.$emit('onVideoMax', that.maxVideo, videoList.length)
          return uni.showToast({
            title: '视频数量已超出',
            duration: 2000,
            icon: 'none'
          });
        }

        const data = Object.assign({}, {
          // 	拍摄视频最长拍摄时间，单位秒。最长支持 60 秒。
          maxDuration: 60,
          // #ifndef MP-TOUTIAO
          // 'front'、'back'，默认'back'
          camera: "back",
          // #endif

          // album 从相册选视频，camera 使用相机拍摄，默认二者都有。
          sourceType: ['camera', 'album'],
          // 是否压缩所选的视频源文件，默认值为 true，需要压缩。
          compressed: true,
          // 'front'、'back'，默认'back'
        }, this.videoFromData)

        uni.chooseVideo({
          ...data,
          success: (res) => {
            let tempFilePath = {...res}
            tempFilePath['path'] = res.tempFilePath

            // 限制视频上传尺寸
            if (that.videoFromData?.size ?? false) {
              const maxSize = that.videoFromData.size * 1024 * 1024

              if (tempFilePath.size > maxSize) {
                uni.showToast({
                  title: `视频最大上传${that.videoFromData.size}MB`,
                  duration: 2000,
                  icon: 'none'
                });
                return false;
              }

            }
            if (that.autoUpload) {
              that.onBeforeUploadFile(tempFilePath, 'video')
            } else {
              that.FileList.push(tempFilePath)
              that.tempFile_paths.push(tempFilePath)
            }
          },
          fail(err) {
            console.error('选择视频失败', err)
          }

        })
      }
    },

    /**
     * 上传前钩子
     * @param { tempFile } 临时文件
     * @return { Promise }
     * */
    onBeforeUploadFile(tempFile) {
      if (this.useBeforeUpload) {
        return this.$emit('beforeUpload', tempFile, () => {
          return this.updataFile(tempFile);
        })
      }
      return this.updataFile(tempFile);
    },

    /**
     * 上传文件到服务器
     * @param { tempFile }  临时文件
     * @return { Promise }
     * */
    updataFile(tempFile) {
      const that = this;
      const filePath = tempFile.path || tempFile;
      const fileType = this.fileUrlType(filePath) == 'image' ? '.png' : '.mp4';
      const fileName = tempFile.name || Date.now() + fileType;

/*      uni.showLoading({
        title: this.loadingText,
        icon: 'loading'
      })*/

      return new Promise((resolve, reject) => {
        this.$emit('startUpload')
        // uniCloud上传
        if (that.action === 'uniCloud') {

          uniCloud.uploadFile({
            cloudPath: String(fileName),
            filePath: filePath,
            // #ifdef MP-ALIPAY
            fileType: fileType,
            // #endif
            cloudPathAsRealPath: this.cloudPathAsRealPath,

            onUploadProgress: (progressEvent) => {
              const percentCompleted = Math.round(
                  (progressEvent.loaded * 100) / progressEvent.total
              );
              that.$emit('onProgress', percentCompleted)
            },
            success(result) {
              if (that.autoUpload) {
                that.FileList.push(result.fileID)
              } else {
                that.FileList.map((item, index) => {
                  if (item === filePath || item.path === filePath) {
                    that.FileList.splice(index, 1, result.fileID)
                  }
                })
              }

              // #ifdef VUE2
              that.$emit('input', that.FileList)
              // #endif
              // #ifdef VUE3
              that.$emit("update:modelValue", that.FileList);
              // #endif

              resolve(result.fileID)
              uni.hideLoading();
              that.$emit('onProgress', {
                ...result
              })
            },
            fail: (error) => {
              uni.hideLoading();
              console.error('error', error);
              that.$emit('onError', error)
              reject(error)
            }
          })
          return false;
        }

        // 接口服务上传
        const uploadTask = uni.uploadFile({
          url: that.action,
          filePath: filePath,
          name: that.fileName,
          formData: that.data,
          header: that.headers,
          // #ifdef MP-ALIPAY
          fileType: filetype,
          // #endif
          success: (uploadFileRes) => {
            const data = JSON.parse(uploadFileRes.data)
            uni.hideLoading();
            that.success(data)

            if (!this.autoUpload) {
              that.FileList.map((item, index) => {
                if (item === filePath || item.path === filePath) {
                  that.FileList.splice(index, 1)
                }
              })
            }

            resolve(data)
          },
          fail: (error) => {
            uni.hideLoading();
            console.error('error', error);
            that.$emit('onError', error)
            reject(error)
          }
        });

        uploadTask.onProgressUpdate((res) => {
          that.$emit('onProgress', {
            ...res,
            ...tempFile
          })
        });
      })
    },

    /**
     * 手动上传
     * */
    submit() {

      return new Promise((resolve, reject) => {
        if (this.tempFile_paths.length <= 0) {
          resolve([])
        }
        console.log('this.tempFile_paths', this.tempFile_paths)
        const uploadedFilePaths = this.tempFile_paths.map(item => {
          return this.onBeforeUploadFile(item || item.path)
        })

        Promise.all(uploadedFilePaths).then(res => {
          this.tempFile_paths = []
          resolve(res)
        }).catch(err => {
          reject(err)
        })
      })

    },

    /**
     * 返回数据
     * @param {array} data 上传成功后的数据
     * @return {array} 返回数据
     * */
    success(data) {
      this.$emit('onSuccess', data);

      // 自定义数据结构-选择性开启
      // const list = data.map(item=> {
      // 	return JSON.parse(item).data.link;
      // })
      // this.$emit('input', [...this.FileList, ...list]);
    },
    /**
     * 压缩图片
     * @param {array} tempFilePaths 临时路径数组
     * @return {array} 被压缩过的路径数组
     * */
    async compressImage(tempFilePaths) {
      const that = this;

      return new Promise((resolve, reject) => {

        if (typeof tempFilePaths !== 'string') {
          console.error('压缩路径错误')
          reject([])
        }

        uni.showLoading({
          title: '压缩中...',
          icon: 'loading',
        })

        // #ifdef H5
        this.canvasDataURL(tempFilePaths, {
          quality: that.imageFormData.quality / 100
        }, (base64Codes) => {
          resolve(base64Codes);
          uni.hideLoading();
        })
        // #endif

        // #ifndef H5
        uni.compressImage({
          src: tempFilePaths,
          quality: that.imageFormData.quality || 80,
          success: res => {
            resolve(res.tempFilePath);
            uni.hideLoading();
          },
          fail(err) {
            reject(err);
            uni.hideLoading();
          }
        })
        // #endif

      })
    },

    /**
     * H5压缩图片质量
     * @param {string} path 图片路径
     * @param {object} obj 压缩配置
     * @param {function} callback 回调函数
     * @return {string} base64
     * */
    canvasDataURL(path, obj, callback) {
      var img = new Image();
      img.src = path;
      img.onload = function () {
        var that = this;
        // 默认按比例压缩
        var w = that.width,
            h = that.height,
            scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        var quality = 0.8; // 默认图片质量为0.8
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        // 创建属性节点
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 图像质量
        if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
          quality = obj.quality;
        }
        // quality值越小，所绘制出的图像越模糊
        var base64 = canvas.toDataURL('image/jpeg', quality);
        // 回调函数返回base64的值
        callback(base64);
      }
    },

    /**
     * 预览图片
     * @param {string, object} item 文件信息
     * */
    previewImage(item) {
      if (this.fileUrlType(item) === 'video') return false;
      if (!this.isPreviewImage) return false;

      const imgs = this.FileList.filter(item => {
        return this.fileUrlType(item) !== 'video'
      }).map(item => item?.path ?? item)
      const current = imgs.indexOf(item || item.path);

      uni.previewImage({
        current: current,
        urls: imgs,
        success() {
        },
        fail(err) {
          console.log(err);
        }
      })
    },

    /**
     * 预览视频
     * @param {string, object} item 文件信息
     * @param {number} index 索引
     * */
    previewVideo(item, index) {
      this.$emit('onVideo', {
        item,
        index
      })
      this.tempVideoUrl = item.path;
    },

    /**
     * 是否img类型
     * @param {string, object} item 文件信息
     * @return {boolean} 是否img类型
     * */
    fileUrlType(file) {
      const filePath = file.path || file;

      if (this.isBase64(filePath)) return 'image'

      const fileType = filePath.split('.').pop();

      const IMAGE_REGEXP = /(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg|image)/i
      if (IMAGE_REGEXP.test(fileType)) {
        return 'image';
      } else {
        return 'video';
      }
    },
    // 判断是否是base64
    isBase64(str) {
      if (str === '' || typeof str !== 'string') return console.error('文件路径错误, base64', str);
      return str.includes('blob:') || str.includes('data:image');
    },
    /**
     * 更新图片临时路径
     * @param newPath
     * @param index
     */
    updateImageTempPath(newPath, index){
      this.FileList[index]=newPath;
      console.log(this.FileList)
      this.tempFile_paths=this.FileList;
    }
  },
}
</script>

<style lang="scss" scoped>
.cl-updata {

  .file-list {
    display: grid;

    &-row {
      display: inline-flex;
      align-items: center;
      position: relative;

      .play-img {
        width: 100%;
      }

      ._image {
        height: 100%;
        width: 100%;
      }

      ._video {
        position: relative;
        width: 100%;
        height: 100%;
        overflow: hidden;
      }

      .video-fixed {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
        border-radius: 10rpx;
        z-index: 96;
      }

      .play {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 30%;
        z-index: 95;
      }

      .app_play {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 50rpx;
        height: 50rpx;
      }

      .remove {
        position: absolute;
        top: 0;
        right: 0;
        background-color: #373737;
        height: 50rpx;
        width: 50rpx;
        border-bottom-left-radius: 200rpx;
        z-index: 97;

        .image {
          width: 20rpx;
          height: 20rpx;
          position: absolute;
          right: 12rpx;
          top: 12rpx;
        }
      }
    }

    .add-image {
      display: flex;
      align-items: center;
      justify-content: center;
      border: 2rpx dashed #ccc;
      width: 100%;
      height: 100%;
      border-radius: 5rpx;

      &:active {
        opacity: 0.8;
      }

      ._image {
        width: 40%;
      }
    }
  }

  .mask {
    background-color: #000;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 99;

    .block {
      padding: 0 30rpx;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 100%;

      .block_video {
        width: 100%;
        height: 78vh;
      }
    }

    ._root {
      width: 60rpx;
      height: 60rpx;
      position: absolute;
      left: 40rpx;
      top: 5vh
    }
  }
}
</style>
